Skip to content

Comments

feat(mpp-idea): migrate DevInEditorInput functionality to mpp-idea module#23

Merged
phodal merged 13 commits intomasterfrom
feature/idea-devin-editor-input
Dec 1, 2025
Merged

feat(mpp-idea): migrate DevInEditorInput functionality to mpp-idea module#23
phodal merged 13 commits intomasterfrom
feature/idea-devin-editor-input

Conversation

@phodal
Copy link
Member

@phodal phodal commented Dec 1, 2025

Summary

Migrate the complete functionality of DevInEditorInput from mpp-ui module to mpp-idea module, with layout reorganization and IDEA-specific integrations.

Changes

1. Create IdeaDevInEditorInput Component

  • Hybrid Swing/Compose UI component
  • Integrates IdeaDevInInput (Swing) with IdeaBottomToolbar (Compose)
  • ConfigManager and PromptEnhancer integration

2. IDEA Completion System Integration

  • Use AutoPopupController to auto-trigger completion on @, /, $, : characters
  • Dynamic DevIn file type detection for syntax highlighting and completion
  • PsiDocumentManager for document-PSI synchronization

3. Toolbar Layout Reorganization

  • Model selector moved to the left side
  • MCP settings and prompt optimization buttons moved to the right side
  • Added AutoAwesome icon for prompt optimization

4. MCP Configuration Dialog

  • Two tabs: Tools and MCP Servers
  • Auto-save functionality (2 seconds delay)
  • Real-time JSON validation
  • Incremental MCP server loading with progress indication

5. Prompt Optimization Dialog

  • Side-by-side display of original and enhanced prompts
  • Auto-enhance on dialog open using PromptEnhancer
  • Support editing enhanced text before applying

Files Changed

File Action
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInEditorInput.kt Created
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaMcpConfigDialog.kt Created
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaPromptOptimizationDialog.kt Created
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.kt Modified
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInInput.kt Modified
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaComposeIcons.kt Modified

Testing

  • Compilation successful
  • JewelRendererTest passed
  • Build successful

Pull Request opened by Augment Code with guidance from the PR author

Summary by CodeRabbit

  • New Features

    • Prompt Optimization dialog + toolbar action
    • MCP Settings dialog for managing tools/servers
    • New top file-selection toolbar with quick actions
    • Optional DevIn-aware editor input and improved insertion flow
    • Several new semantic icons for toolbars/dialogs
  • UI Improvements

    • Resizable split panes for main layout
    • Model selector hover/visual refinements
    • Bottom toolbar reorganized; token count shown as text
  • Removed

    • Workspace indicator and legacy @ / trigger buttons
    • Old multiline input composite

✏️ Tip: You can customize this high-level summary in your review settings.

Deleted obsolete IdeaInputSection to clean up the codebase.
- Move model selector to left side of toolbar
- Add MCP settings and prompt optimization buttons to right side
- Create IdeaDevInEditorInput component with hybrid Swing/Compose UI
- Add AutoAwesome icon for prompt optimization
- Initialize PromptEnhancer and ConfigManager integration
- Add placeholders for dialogs (to be implemented)
- Add auto-completion trigger for @, /, $, : characters
- Try to use DevIn file type if available for syntax highlighting
- Integrate with AutoPopupController for programmatic completion
- Add PsiDocumentManager for document-PSI synchronization
- Fall back to plain text if DevIn language is not available
- Create IdeaMcpConfigDialog with two tabs: Tools and MCP Servers
- Implement auto-save functionality with 2 seconds delay
- Add real-time JSON validation for MCP server configuration
- Support incremental MCP server loading with progress indication
- Use Jewel UI components (DefaultButton, OutlinedButton, Checkbox, etc.)
- Integrate with IdeaDevInEditorInput component
- Create IdeaPromptOptimizationDialog with side-by-side comparison
- Display original and enhanced prompts
- Auto-enhance on dialog open using PromptEnhancer
- Allow editing of enhanced text before applying
- Integrate with IdeaDevInEditorInput component
- Support Ctrl+P keyboard shortcut (via toolbar button)
@coderabbitai
Copy link

coderabbitai bot commented Dec 1, 2025

Caution

Review failed

The pull request is closed.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Refactors IDE editor UI: removes IdeaInputSection, updates bottom/top toolbars, adds MCP config and prompt-optimization dialogs, integrates DevIn PSI-backed documents and AutoPopup, swaps kotlinx-serialization for Gson in remote client, adds new icons, and updates Gradle/IDE plugin configuration for DevIn support.

Changes

Cohort / File(s) Summary
Bottom toolbar & input surface
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.kt, mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaInputSection.kt
Removed IdeaInputSection and InputHints. IdeaBottomToolbar API changed: removed workspacePath param, added onPromptOptimizationClick: () -> Unit. Layout/wiring updated (token label, MCP Settings, Prompt Optimization button, removed dedicated @// triggers).
DevIn-aware editor input
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInInput.kt
Uses PSI-backed document creation via PsiFileFactory/PsiDocumentManager for DevIn language, exposes project as private property, replaces raw inserts with InsertUtil.insertStringAndSaveChange, and triggers IntelliJ AutoPopup completion on trigger chars.
Prompt optimization dialog
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaPromptOptimizationDialog.kt
New composable IdeaPromptOptimizationDialog(...) that optionally auto-enhances text asynchronously, shows original vs editable enhanced text, displays status/errors, and provides Cancel/Apply callbacks.
MCP configuration dialog
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaMcpConfigDialog.kt
New composable IdeaMcpConfigDialog(onDismiss) with Tools and MCP Servers tabs, JSON editor/reload, debounced auto-save for tool configs, loading/error states, and callbacks for incremental tool loading.
Top toolbar & icons
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaTopToolbar.kt, mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaComposeIcons.kt
Added IdeaTopToolbar composable and SelectedFileItem data class. Introduced seven new ImageVector icons: SmartToy, AutoAwesome, ContentPaste, Save, TextFields, InsertDriveFile, Close.
Model selector UI tweak
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaModelSelector.kt
Replaced OutlinedButton with hover-responsive Row, added hover interaction source/state and updated popup content/positioning while preserving selection behavior.
Agent app layout refactor
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaAgentApp.kt
Reworked main content into IdeaVerticalResizableSplitPane for CODING/LOCAL_CHAT and REMOTE agents; unified top/bottom panes with IdeaDevInInputArea; removed onAtClick/onSlashClick wiring and adjusted pane sizing and rendering.
Remote client JSON handling
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/remote/IdeaRemoteAgentClient.kt
Replaced kotlinx-serialization with Gson: removed @Serializable annotations, uses gson.fromJson/gson.toJson for request/response bodies; preserved existing control flow for health checks, project fetch, and SSE streaming.
Build and settings
mpp-idea/build.gradle.kts, mpp-idea/settings.gradle.kts, mpp-idea/gradle.properties
Removed Kotlin serialization plugin and kotlinx-serialization-json dep; added Gson and AutoDev-Intellij dependencies (with excludes); updated bundled plugins (markdown, sh, Git4Idea); bumped Kotlin plugin versions; added dependency substitutions and Gradle properties (JVM args, caching, kotlin.stdlib flag).
Plugin descriptor
mpp-idea/src/main/resources/META-INF/plugin.xml
Added xi namespace and xi:include for DevIn language, updated description, added plugin dependencies (markdown, sh, Git4Idea), and declared several new extensionPoints for DevIn integration.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Areas needing extra attention:
    • All call sites and usages of IdeaBottomToolbar (signature change: removal of workspacePath, addition of onPromptOptimizationClick).
    • Deleted IdeaInputSection.kt — search project for references or tests that still reference it.
    • PSI document creation, InsertUtil usage, and AutoPopupController integration in IdeaDevInInput.kt (threading/commit/DocumentManager interactions).
    • Async enhancement flow, cancellation, and UI state/error handling in IdeaPromptOptimizationDialog.kt.
    • Gson migration in IdeaRemoteAgentClient.kt (ensure JSON shapes match previous behavior and SSE parsing remains robust).
    • Build config changes (dependency excludes/substitutions) and plugin.xml extension points consistency.

Possibly related PRs

Poem

🐰 I hopped through code with nimble paws, anew,
Dialogs bloom, icons gleam — a joyous view,
DevIn whispers, popups wake, tokens softly show,
Panes stretch and widgets dance in tidy rows,
A little rabbit cheers — apply, save, and go!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 19.23% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately summarizes the main change: migrating DevInEditorInput functionality to the mpp-idea module, which is the core objective of this PR.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a989c1f and fffab93.

📒 Files selected for processing (6)
  • mpp-idea/build.gradle.kts (2 hunks)
  • mpp-idea/gradle.properties (1 hunks)
  • mpp-idea/settings.gradle.kts (2 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInInput.kt (5 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/remote/IdeaRemoteAgentClient.kt (5 hunks)
  • mpp-idea/src/main/resources/META-INF/plugin.xml (1 hunks)

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@augmentcode augmentcode bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 1 suggestions posted.

Comment augment review to trigger a new review at any time.

val scope = rememberCoroutineScope()

// Create the input component
val inputComponent = remember {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid leaks, consider registering inputComponent with the parent disposable via Disposer.register(disposable, inputComponent) so its dispose() runs when the parent is disposed (preventing dangling document listeners/message bus connections). (Guideline: no_memory_leaks)

🤖 Was this useful? React with 👍 or 👎

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (8)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaMcpConfigDialog.kt (4)

36-42: Consider logging serialization failures.

The function silently returns "{}" on serialization errors, which may hide configuration issues during debugging. Consider logging the exception for troubleshooting purposes.

 private fun serializeMcpConfig(servers: Map<String, McpServerConfig>): String {
     return try {
         json.encodeToString(servers)
     } catch (e: Exception) {
+        println("⚠️ Failed to serialize MCP config: ${e.message}")
         "{}"
     }
 }

114-164: Redundant nested scope.launch in LaunchedEffect.

The inner scope.launch on line 121 is redundant since LaunchedEffect already provides a coroutine scope. This creates an extra coroutine unnecessarily.

     LaunchedEffect(Unit) {
-        scope.launch {
             try {
                 toolConfig = ConfigManager.loadToolConfig()
                 mcpConfigJson = serializeMcpConfig(toolConfig.mcpServers)
 
                 if (toolConfig.mcpServers.isNotEmpty()) {
-                    scope.launch {
+                    // No need for nested launch - already in coroutine scope
                         // Create callback for incremental loading
                         val callback = object : McpLoadingStateCallback {
                             // ... callback implementation
                         }
                         // ... rest of loading logic
-                    }
                 }
 
                 isLoading = false
             } catch (e: Exception) {
                 // ... error handling
             }
-        }
     }

276-294: Duplicate callback object definition.

The McpLoadingStateCallback implementation is duplicated here (lines 276-289) and in the initial loading (lines 123-140). Consider extracting to a helper function to reduce code duplication.

// Extract to a helper function outside the composable or at the top of the function:
fun createLoadingCallback(
    onStateUpdate: (McpLoadingState) -> Unit,
    onToolsUpdate: (String, List<ToolItem>) -> Unit
): McpLoadingStateCallback = object : McpLoadingStateCallback {
    override fun onServerStateChanged(serverName: String, state: McpServerState) {
        // ... implementation
    }
    override fun onLoadingStateChanged(loadingState: McpLoadingState) {
        onStateUpdate(loadingState)
    }
    override fun onBuiltinToolsLoaded(tools: List<ToolItem>) {
        // ... implementation
    }
}

416-425: JSON editor lacks visual styling.

The BasicTextField for MCP server JSON configuration lacks visual boundaries (e.g., background, border), making it hard to distinguish from surrounding content and potentially confusing for users.

         BasicTextField(
             state = textFieldState,
-            modifier = Modifier.fillMaxWidth().weight(1f),
+            modifier = Modifier
+                .fillMaxWidth()
+                .weight(1f)
+                .background(JewelTheme.globalColors.panelBackground)
+                .padding(8.dp),
             textStyle = TextStyle(
                 fontFamily = androidx.compose.ui.text.font.FontFamily.Monospace,
                 color = org.jetbrains.jewel.foundation.theme.JewelTheme.globalColors.text.normal
             ),
             cursorBrush = SolidColor(org.jetbrains.jewel.foundation.theme.JewelTheme.globalColors.text.normal)
         )
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaPromptOptimizationDialog.kt (2)

43-43: Unused variable scope.

The rememberCoroutineScope() result is assigned to scope but never used, as LaunchedEffect provides its own scope.

-    val scope = rememberCoroutineScope()

108-118: Inconsistent BasicTextField API usage.

The original text field uses the value/onValueChange pattern while the enhanced text field uses the state pattern. For consistency and future maintainability, consider using the same approach for both.

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInEditorInput.kt (2)

110-110: Inline fully-qualified class name should be imported.

cc.unitmesh.indexer.DomainDictService is referenced inline. Consider adding it to the imports for consistency and readability.

+import cc.unitmesh.indexer.DomainDictService
 // ...
-val domainDictService = cc.unitmesh.indexer.DomainDictService(fileSystem)
+val domainDictService = DomainDictService(fileSystem)

104-112: Non-null assertion after null check could use safer Kotlin idioms.

Using currentModelConfig!! after checking currentModelConfig != null works but is less idiomatic. Consider using let or a local variable.

-                if (currentModelConfig != null && currentModelConfig!!.isValid()) {
-                    llmService = KoogLLMService.create(currentModelConfig!!)
+                currentModelConfig?.takeIf { it.isValid() }?.let { config ->
+                    llmService = KoogLLMService.create(config)
 
                     val workspace = WorkspaceManager.currentWorkspace
                     if (workspace != null) {
                         val fileSystem = workspace.fileSystem
-                        val domainDictService = cc.unitmesh.indexer.DomainDictService(fileSystem)
-                        promptEnhancer = PromptEnhancer(llmService!!, fileSystem, domainDictService)
+                        val domainDictService = DomainDictService(fileSystem)
+                        promptEnhancer = PromptEnhancer(llmService!!, fileSystem, domainDictService)
                     }
                 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 92a5b3c and 107c4d1.

📒 Files selected for processing (7)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.kt (5 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInEditorInput.kt (1 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInInput.kt (5 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaInputSection.kt (0 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaMcpConfigDialog.kt (1 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaPromptOptimizationDialog.kt (1 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaComposeIcons.kt (1 hunks)
💤 Files with no reviewable changes (1)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaInputSection.kt
🧰 Additional context used
📓 Path-based instructions (1)
**/*.kt

📄 CodeRabbit inference engine (AGENTS.md)

Use expect/actual for platform-specific code in KMP projects (e.g., file I/O on JVM/JS/Wasm)

Files:

  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaMcpConfigDialog.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaPromptOptimizationDialog.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInEditorInput.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaComposeIcons.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInInput.kt
🧬 Code graph analysis (2)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.kt (1)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaModelSelector.kt (1)
  • IdeaModelSelector (33-130)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInEditorInput.kt (3)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.kt (1)
  • IdeaBottomToolbar (30-239)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaMcpConfigDialog.kt (1)
  • IdeaMcpConfigDialog (64-328)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaPromptOptimizationDialog.kt (1)
  • IdeaPromptOptimizationDialog (32-185)
🔇 Additional comments (7)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaComposeIcons.kt (1)

1258-1304: LGTM!

The AutoAwesome icon follows the established pattern in this file: lazy initialization, consistent 24dp dimensions, and standard path-based vector definition. The three-star design appropriately conveys AI/optimization functionality.

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.kt (2)

39-39: LGTM!

The new onPromptOptimizationClick callback parameter is properly added with a default empty lambda for backward compatibility. The toolbar layout reorganization aligns with the PR objectives.


177-188: LGTM!

The new Prompt Optimization button is well-integrated with appropriate sizing, accessibility description, and the new AutoAwesome icon. Placement alongside MCP Settings on the right side is logical.

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInInput.kt (3)

57-64: LGTM!

The lazy DevIn file type detection with safe fallback is appropriate for optional language support. Broad exception handling is acceptable here since the feature gracefully degrades.


209-224: LGTM!

The document recreation logic properly handles DevIn language support with appropriate fallbacks. Using ReadAction.compute ensures thread safety, and the PSI-based document creation enables syntax highlighting and completion.


256-270: LGTM!

The auto-completion trigger for special characters (@, /, $, :) enhances UX by automatically showing relevant completions. Proper document commit before triggering the popup ensures PSI synchronization.

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInEditorInput.kt (1)

58-68: LGTM!

The IdeaDevInInput component is properly created with remember for Compose state management, and correctly wired with the project and disposable for IntelliJ lifecycle integration.

inputComponent.clearInput()
}
},
sendEnabled = inputComponent.text.isNotBlank(),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

sendEnabled won't update reactively.

inputComponent.text.isNotBlank() is evaluated at composition time but won't trigger recomposition when the Swing text changes. The Send button's enabled state won't update as the user types.

Consider tracking the input text in Compose state and updating it from the IdeaInputListener.onTextChanged callback:

+    var inputText by remember { mutableStateOf(initialText) }
+    
     // Add submit listener
     DisposableEffect(Unit) {
         val listener = object : IdeaInputListener {
             // ...
             override fun onTextChanged(text: String) {
-                // Handle text changes if needed
+                inputText = text
             }
             // ...
         }
         // ...
     }
     
     // In IdeaBottomToolbar:
-    sendEnabled = inputComponent.text.isNotBlank(),
+    sendEnabled = inputText.isNotBlank(),

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInEditorInput.kt
around line 143, the sendEnabled value is computed from
inputComponent.text.isNotBlank() at composition time and therefore won't update
on text changes; fix by introducing a Compose mutableStateOf<String> (e.g.
inputText) to hold the current text, initialize it from inputComponent.text,
update that state inside the IdeaInputListener.onTextChanged callback, and then
use inputText.isNotBlank() for sendEnabled so Compose recomposes correctly when
the user types; ensure the listener updates are posted to the UI thread if
necessary and remove/unregister the listener when the composable is disposed.

Comment on lines 177 to 182
// Model Configuration Dialog
if (showModelConfigDialog) {
// TODO: Create IDEA version of model configuration dialog
// For now, just close it
showModelConfigDialog = false
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Model configuration dialog placeholder immediately dismisses.

The TODO placeholder immediately sets showModelConfigDialog = false, causing the dialog to never appear. This creates a confusing user experience where clicking "Configure Model..." has no visible effect.

Consider showing a placeholder message or disabling the configure option until implemented:

     if (showModelConfigDialog) {
-        // TODO: Create IDEA version of model configuration dialog
-        // For now, just close it
-        showModelConfigDialog = false
+        Dialog(onDismissRequest = { showModelConfigDialog = false }) {
+            Column(modifier = Modifier.padding(16.dp)) {
+                Text("Model Configuration")
+                Spacer(modifier = Modifier.height(8.dp))
+                Text("Coming soon - use Settings to configure models")
+                Spacer(modifier = Modifier.height(16.dp))
+                DefaultButton(onClick = { showModelConfigDialog = false }) {
+                    Text("OK")
+                }
+            }
+        }
     }

Committable suggestion skipped: line range outside the PR's diff.

isEnhancing = true
errorMessage = null
try {
val enhanced = enhancer.enhance(originalText.trim(), "zh")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Hardcoded language code "zh" limits internationalization.

The language is hardcoded to "zh" (Chinese), which may not be appropriate for all users. Consider making this configurable or detecting the user's locale.

+// Consider adding a parameter or detecting system locale
+val userLanguage = java.util.Locale.getDefault().language
 val enhanced = enhancer.enhance(originalText.trim(), "zh")
+// Or pass as parameter: enhancer.enhance(originalText.trim(), userLanguage)

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaPromptOptimizationDialog.kt
around line 51, the enhancer call uses a hardcoded language code "zh"; replace
this with a configurable or locale-driven value. Fetch the user's preferred
language from plugin settings or detect Locale.getDefault().language,
validate/normalize the code (fallback to "en" if unsupported), and pass that
variable into enhancer.enhance(originalText.trim(), languageCode) so the UI
respects user locale or configuration.

horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text("Prompt Optimization (Ctrl+P)")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for Ctrl+P shortcut registration and related prompt optimization shortcuts
rg -n -i "ctrl.*p|prompt.*shortcut|VK_P" --type=kt -A 3 -B 3

Repository: phodal/auto-dev-sketch

Length of output: 92


🏁 Script executed:

#!/bin/bash
# Search for Ctrl+P and shortcut-related patterns without type restriction
rg -n "Ctrl.*P|ctrl.*p|VK_P|vk_p|KeyEvent.VK_P" --max-count=20

Repository: phodal/auto-dev-sketch

Length of output: 2813


🏁 Script executed:

#!/bin/bash
# Find and examine the IdeaPromptOptimizationDialog.kt file
find . -name "IdeaPromptOptimizationDialog.kt" -type f

Repository: phodal/auto-dev-sketch

Length of output: 155


🏁 Script executed:

#!/bin/bash
# Search for prompt optimization related shortcuts and actions
rg -n "PromptOptimization|prompt.*optimization" -i | head -30

Repository: phodal/auto-dev-sketch

Length of output: 3040


🏁 Script executed:

#!/bin/bash
# Read the IdeaPromptOptimizationDialog.kt file
cat -n ./mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaPromptOptimizationDialog.kt

Repository: phodal/auto-dev-sketch

Length of output: 8466


🏁 Script executed:

#!/bin/bash
# Check IdeaDevInEditorInput.kt to see how the dialog is used and if shortcuts are handled there
cat -n ./mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInEditorInput.kt | head -200

Repository: phodal/auto-dev-sketch

Length of output: 8559


Remove "(Ctrl+P)" from dialog header or implement the shortcut for IntelliJ IDEA.

The Ctrl+P shortcut is not registered for the IntelliJ IDEA plugin dialog. While Ctrl+P is implemented in the shared UI code (mpp-ui), the IDEA-specific dialog at mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaPromptOptimizationDialog.kt:85 is opened only via button click (line 157–158 in IdeaDevInEditorInput.kt). Either remove the "(Ctrl+P)" text to avoid misleading users, or register the keyboard shortcut in the IDEA editor context.

🤖 Prompt for AI Agents
In
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaPromptOptimizationDialog.kt
around line 85, the dialog header contains the misleading text "(Ctrl+P)";
either remove that text from the header or register the Ctrl+P shortcut to
actually open the dialog. To fix: simplest approach—remove the "(Ctrl+P)"
substring from the Text(...) at line 85. If you prefer to keep the hint,
implement the shortcut by exposing an IntelliJ action that opens this dialog (or
reuse the existing opener at IdeaDevInEditorInput.kt lines 157–158), register
that action in plugin.xml (or create a DumbAware AnAction) and bind the Ctrl+P
ShortcutSet (or registerCustomShortcutSet on the editor component) so pressing
Ctrl+P opens the dialog in the editor context.

- Add SmartToy icon for model selector (robot/AI icon)
- Make model selector blend with background using hover effects
- Remove workspace/project name display (not needed in IDEA)
- Add border and rounded corners to IdeaDevInEditorInput
- Add padding to editor panel for better spacing
- Simplify token display to compact format (e.g., '1234t')
- Reduce toolbar padding for cleaner look
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (3)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInEditorInput.kt (3)

63-73: Ensure IdeaDevInInput is properly disposed to avoid leaks.

inputComponent is created and remembered but never explicitly tied to the passed disposable. If IdeaDevInInput registers document listeners / message-bus subscriptions, this risks leaks when the parent is disposed.

Consider registering it with the parent disposable (or otherwise wiring its lifecycle) if it implements Disposable, e.g.:

val inputComponent = remember {
    IdeaDevInInput(
        project = project,
        listeners = emptyList(),
        disposable = disposable,
        showAgent = true
    ).apply {
        text = initialText
        // If IdeaDevInInput is Disposable:
        // Disposer.register(disposable, this)
    }
}

75-97: Send button enablement is not reactive to text changes.

sendEnabled = inputComponent.text.isNotBlank() is evaluated during composition, but Compose isn’t observing inputComponent.text, so typing in the Swing editor won’t automatically recompose and update the enabled state.

Track the text in Compose state and update it from IdeaInputListener.onTextChanged:

var inputText by remember { mutableStateOf(initialText) }

DisposableEffect(Unit) {
    val listener = object : IdeaInputListener {
        override fun onSubmit(text: String, trigger: IdeaInputTrigger) {
            onSubmit(text)
            inputComponent.clearInput()
            inputText = "" // keep state in sync
        }

        override fun onTextChanged(text: String) {
            inputText = text
        }

        override fun editorAdded(editor: com.intellij.openapi.editor.ex.EditorEx) { }
    }

    inputComponent.addInputListener(listener)
    onDispose { inputComponent.removeInputListener(listener) }
}

IdeaBottomToolbar(
    onSendClick = {
        val text = inputComponent.text.trim()
        if (text.isNotEmpty()) {
            onSubmit(text)
            inputComponent.clearInput()
            inputText = ""
        }
    },
    sendEnabled = inputText.isNotBlank(),
    // ...
)

Ensure programmatic updates (e.g., from prompt optimization) also drive inputText via onTextChanged or explicit state updates.

Also applies to: 150-160


192-197: Model config dialog flag is immediately reset, so UI never appears.

When showModelConfigDialog becomes true, this branch runs once and immediately sets it back to false, with no UI. From the user’s perspective, clicking “Configure” appears to do nothing.

If the real dialog isn’t ready yet, show a minimal placeholder dialog or disable the configure action until implemented. For example:

if (showModelConfigDialog) {
    Dialog(onDismissRequest = { showModelConfigDialog = false }) {
        Column(Modifier.padding(16.dp)) {
            Text("Model configuration is not yet available in this build.")
            Spacer(Modifier.height(16.dp))
            DefaultButton(onClick = { showModelConfigDialog = false }) {
                Text("OK")
            }
        }
    }
}
🧹 Nitpick comments (7)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaModelSelector.kt (2)

46-73: Hover interaction wiring looks solid; consider sharing interactionSource with clickable

The hover-based background and expanded coupling are clean and keep the selector visually lightweight. One small improvement: you can pass the same interactionSource into clickable so hover/press states share a single source and you avoid creating an extra one under the hood.

For example:

Row(
    modifier = Modifier
        .clip(RoundedCornerShape(6.dp))
        .hoverable(interactionSource = interactionSource)
        .background(
            if (isHovered || expanded)
                JewelTheme.globalColors.borders.normal.copy(alpha = 0.3f)
            else
                Color.Transparent
        )
        .clickable(
            interactionSource = interactionSource,
            indication = null, // or keep default if you want ripple
        ) { expanded = true }
        .padding(horizontal = 8.dp, vertical = 6.dp),
    ...
)

Purely optional, but keeps interaction state centralized.


74-93: Handle long model names more gracefully in the selector label

The inline label composition looks good, but with maxLines = 1 and no width/overflow control, very long model names may either stretch the toolbar or get hard-clipped.

You might want to constrain and ellipsize the text, for example:

Text(
    text = displayText,
    style = JewelTheme.defaultTextStyle.copy(
        fontSize = 12.sp,
        color = JewelTheme.globalColors.text.normal
    ),
    maxLines = 1,
    modifier = Modifier.weight(1f),
    overflow = TextOverflow.Ellipsis,
)

This keeps the selector compact while still signaling truncated content.

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.kt (3)

24-30: KDoc matches the new layout; consider slightly clarifying the right‑side description

The KDoc correctly documents the new layout, but the bullet “Right side: MCP and prompt optimization” omits the @, /, and send/stop actions.

If you want it to be fully explicit, a minor tweak like this would help:

- * - Right side: MCP and prompt optimization
+ * - Right side: action triggers (@, /), MCP settings, prompt optimization, send/stop

49-80: Left‑side layout and token indicator look solid; consider making the token display a bit clearer

The model selector integration and subtle token text ("${totalTokens}t") are implemented cleanly and match the described layout.

If you expect non‑expert users, you might consider a slightly clearer label or a tooltip (e.g., “123 tokens”) instead of the bare "123t", but this is purely UX polish.


82-139: Right‑side actions and prompt optimization button are wired correctly; optional enable/disable control

The right‑side cluster wiring (MCP settings + new prompt optimization button) looks correct, with appropriate contentDescriptions and consistent icon sizing.

If there are cases where prompt optimization should be disabled (e.g., empty input or optimization already running), you might want to add a dedicated promptOptimizationEnabled flag, similar to sendEnabled, and thread it through:

 fun IdeaBottomToolbar(
     onSendClick: () -> Unit,
     sendEnabled: Boolean,
@@
-    onSettingsClick: () -> Unit = {},
-    onPromptOptimizationClick: () -> Unit = {},
+    onSettingsClick: () -> Unit = {},
+    onPromptOptimizationClick: () -> Unit = {},
+    promptOptimizationEnabled: Boolean = true,
@@
-            IconButton(
-                onClick = onPromptOptimizationClick,
-                modifier = Modifier.size(32.dp)
-            ) {
+            IconButton(
+                onClick = onPromptOptimizationClick,
+                enabled = promptOptimizationEnabled,
+                modifier = Modifier.size(32.dp)
+            ) {

Totally optional, depending on how the dialog is used.

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInEditorInput.kt (2)

37-48: initialText / placeholder are effectively write‑only props.

initialText is applied once in the remember block, and placeholder is currently unused. If callers expect these parameters to be honored when they change over time (e.g., loading a draft or showing contextual placeholders), the current wiring won’t update the Swing component.

If dynamic updates are desired, consider:

  • Passing placeholder through to IdeaDevInInput (if it supports it), and
  • Syncing initialText via a side effect keyed on it:
LaunchedEffect(initialText) {
    if (inputComponent.text != initialText) {
        inputComponent.text = initialText
    }
}

Otherwise, consider documenting that they are only used at first composition or trimming unused parameters.

Also applies to: 63-73


206-217: Guard prompt optimization when no enhancer is available.

IdeaPromptOptimizationDialog is always opened when showPromptOptimizationDialog is true, with enhancer = promptEnhancer. If promptEnhancer is null (e.g., config load failed, invalid model, or no workspace), the dialog implementation must handle that gracefully.

If IdeaPromptOptimizationDialog does not support a null enhancer, consider:

  • Disabling or hiding the prompt optimization button until promptEnhancer is non-null, or
  • Showing a message in place of optimization (e.g., “Configure a valid model to enable prompt optimization”).
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 107c4d1 and cac9edc.

📒 Files selected for processing (5)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.kt (4 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInEditorInput.kt (1 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaModelSelector.kt (4 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaAgentApp.kt (0 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaComposeIcons.kt (1 hunks)
💤 Files with no reviewable changes (1)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaAgentApp.kt
🧰 Additional context used
📓 Path-based instructions (1)
**/*.kt

📄 CodeRabbit inference engine (AGENTS.md)

Use expect/actual for platform-specific code in KMP projects (e.g., file I/O on JVM/JS/Wasm)

Files:

  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaComposeIcons.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInEditorInput.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaModelSelector.kt
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build (223)
  • GitHub Check: Build (241)
🔇 Additional comments (3)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaComposeIcons.kt (1)

1258-1362: LGTM! Clean icon additions following established patterns.

Both SmartToy and AutoAwesome icons are well-implemented and consistent with the existing icon definitions in this file. They correctly use lazy initialization, standard 24×24 dp dimensions, appropriate path definitions with helpful comments, and proper KDoc documentation.

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.kt (1)

32-48: New onPromptOptimizationClick callback is a clean, backwards‑friendly API extension

Adding onPromptOptimizationClick: () -> Unit = {} with a default no‑op is a reasonable way to expose the new action without breaking existing Kotlin call sites, and the parameter ordering matches the visual button order.

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInEditorInput.kt (1)

99-123: Cannot verify the specific code at the mentioned lines as the file is not present in the repository.

The original review identifies a legitimate architectural issue: if active model configuration changes are handled in onConfigSelect (lines 177-185) without calling a function to reinitialize llmService and promptEnhancer, then configuration changes would not be reflected in the runtime behavior. The suggested fix—extracting the initialization logic into a reusable function called both on load and on config change—is a sound pattern for Kotlin/Compose applications.

However, without access to the actual code at the referenced lines (99-123 and 177-185), I cannot:

  • Confirm whether onConfigSelect actually lacks the reinitialization logic
  • Verify if there's alternative handling elsewhere (e.g., through observers, reactive properties, or other mechanisms)
  • Determine the full scope of the issue

- Create IdeaTopToolbar component with @ and / triggers moved from bottom
- Add file selection buttons (clipboard, save, cursor, add file)
- Add file chips display with remove functionality
- Add new icons: ContentPaste, Save, TextFields, InsertDriveFile, Close
- Simplify IdeaBottomToolbar by removing @ and / buttons
- Update IdeaDevInEditorInput to use new top toolbar layout
- Update IdeaAgentApp to match new toolbar API
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (3)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInEditorInput.kt (3)

64-73: Register inputComponent with parent disposable to prevent leaks.

The inputComponent is created but not explicitly registered with the parent disposable, which could lead to resource leaks if IdeaDevInInput holds document listeners or message bus connections.

Consider registering with:

val inputComponent = remember {
    IdeaDevInInput(
        project = project,
        listeners = emptyList(),
        disposable = disposable,
        showAgent = true
    ).apply {
        text = initialText
        Disposer.register(disposable, this)
    }
}

Based on past review comment.


184-184: sendEnabled won't update reactively when user types.

inputComponent.text.isNotBlank() is evaluated at composition time but won't trigger recomposition when the Swing text changes. The Send button's enabled state will remain stale.

Track the input text in Compose state and update it from the IdeaInputListener.onTextChanged callback:

+    var inputText by remember { mutableStateOf(initialText) }
+
     // Add submit listener
     DisposableEffect(Unit) {
         val listener = object : IdeaInputListener {
             // ...
             override fun onTextChanged(text: String) {
-                // Handle text changes if needed
+                inputText = text
             }
             // ...
         }
         // ...
     }
     
     // In IdeaBottomToolbar:
-    sendEnabled = inputComponent.text.isNotBlank(),
+    sendEnabled = inputText.isNotBlank(),

Based on past review comment.


204-208: Model configuration dialog immediately dismisses.

The TODO placeholder sets showModelConfigDialog = false immediately, so clicking "Configure Model..." has no visible effect.

Consider showing a placeholder message or temporarily disabling the configure option:

     if (showModelConfigDialog) {
-        // TODO: Create IDEA version of model configuration dialog
-        // For now, just close it
-        showModelConfigDialog = false
+        org.jetbrains.jewel.ui.component.Dialog(
+            onDismissRequest = { showModelConfigDialog = false }
+        ) {
+            Column(modifier = Modifier.padding(16.dp)) {
+                Text("Model Configuration")
+                Spacer(modifier = Modifier.height(8.dp))
+                Text("Coming soon - use Settings to configure models")
+                Spacer(modifier = Modifier.height(16.dp))
+                org.jetbrains.jewel.ui.component.DefaultButton(
+                    onClick = { showModelConfigDialog = false }
+                ) {
+                    Text("OK")
+                }
+            }
+        }
     }

Based on past review comment.

🧹 Nitpick comments (2)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInEditorInput.kt (2)

108-118: Prefer idiomatic null handling over !! operator.

The null check followed by !! is safe but not idiomatic. Consider using ?.let for cleaner, more Kotlin-style code.

-                // Initialize LLM service and prompt enhancer
-                if (currentModelConfig != null && currentModelConfig!!.isValid()) {
-                    llmService = KoogLLMService.create(currentModelConfig!!)
-
-                    val workspace = WorkspaceManager.currentWorkspace
-                    if (workspace != null) {
-                        val fileSystem = workspace.fileSystem
-                        val domainDictService = cc.unitmesh.indexer.DomainDictService(fileSystem)
-                        promptEnhancer = PromptEnhancer(llmService!!, fileSystem, domainDictService)
-                    }
-                }
+                // Initialize LLM service and prompt enhancer
+                currentModelConfig?.takeIf { it.isValid() }?.let { config ->
+                    llmService = KoogLLMService.create(config)
+
+                    WorkspaceManager.currentWorkspace?.let { workspace ->
+                        val fileSystem = workspace.fileSystem
+                        val domainDictService = cc.unitmesh.indexer.DomainDictService(fileSystem)
+                        promptEnhancer = PromptEnhancer(llmService!!, fileSystem, domainDictService)
+                    }
+                }

141-154: Toolbar actions have placeholder implementations.

Several toolbar actions (clipboard paste, save to workspace, insert current selection, file picker) are marked with TODO comments and not yet implemented.

These incomplete features may affect user experience. Do you want me to open an issue to track implementing these actions, or would you like help generating the implementation code?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cac9edc and 593d4ca.

📒 Files selected for processing (5)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.kt (3 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInEditorInput.kt (1 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaTopToolbar.kt (1 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaAgentApp.kt (0 hunks)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaComposeIcons.kt (1 hunks)
💤 Files with no reviewable changes (1)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaAgentApp.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.kt
🧰 Additional context used
📓 Path-based instructions (1)
**/*.kt

📄 CodeRabbit inference engine (AGENTS.md)

Use expect/actual for platform-specific code in KMP projects (e.g., file I/O on JVM/JS/Wasm)

Files:

  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaTopToolbar.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInEditorInput.kt
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaComposeIcons.kt
🧬 Code graph analysis (1)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaDevInEditorInput.kt (4)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaTopToolbar.kt (1)
  • IdeaTopToolbar (30-122)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaBottomToolbar.kt (1)
  • IdeaBottomToolbar (30-159)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaMcpConfigDialog.kt (1)
  • IdeaMcpConfigDialog (64-328)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaPromptOptimizationDialog.kt (1)
  • IdeaPromptOptimizationDialog (32-185)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build (241)
  • GitHub Check: Build (223)
🔇 Additional comments (2)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaComposeIcons.kt (1)

1258-1542: LGTM! Clean icon additions.

The seven new icon definitions (SmartToy, AutoAwesome, ContentPaste, Save, TextFields, InsertDriveFile, Close) follow the established pattern and are implemented consistently with existing icons in this file.

mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaTopToolbar.kt (1)

1-189: LGTM! Well-structured toolbar implementation.

The toolbar implementation follows Compose best practices with proper hover state management, tooltips, and clean separation of concerns. The conditional separator and hover-to-show close button provide good UX.

Deleted IdeaDevInEditorInput.kt as it is no longer needed.
- Use IdeaVerticalResizableSplitPane to separate timeline content and input area
- Allow dynamic resizing of input area (30% to 90% of available space)
- Initial split ratio set to 75% for content, 25% for input
- Apply resizable layout to CODING, LOCAL_CHAT, and REMOTE agent types
- CODE_REVIEW and KNOWLEDGE modes use fixed layout (no input area)
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaAgentApp.kt (1)

325-345: Stale closure bug: isProcessing won't update inside SwingPanel factory.

The isProcessing parameter is captured when the SwingPanel factory lambda executes (once on creation). Subsequent recompositions with updated isProcessing values won't affect the listener's !isProcessing check on line 331, allowing users to trigger onSend even while processing.

Use rememberUpdatedState to ensure the listener sees the current value:

 private fun IdeaDevInInputArea(
     ...
     isProcessing: Boolean,
     ...
 ) {
     var inputText by remember { mutableStateOf("") }
     var devInInput by remember { mutableStateOf<IdeaDevInInput?>(null) }
+    val currentIsProcessing by rememberUpdatedState(isProcessing)
+    val currentOnSend by rememberUpdatedState(onSend)
+    val currentOnAbort by rememberUpdatedState(onAbort)
 
     Column(
         ...
                     addInputListener(object : IdeaInputListener {
                         ...
                         override fun onSubmit(text: String, trigger: IdeaInputTrigger) {
-                            if (text.isNotBlank() && !isProcessing) {
-                                onSend(text)
+                            if (text.isNotBlank() && !currentIsProcessing) {
+                                currentOnSend(text)
                                 clearInput()
                                 inputText = ""
                             }
                         }
 
                         override fun onStop() {
-                            onAbort()
+                            currentOnAbort()
                         }
🧹 Nitpick comments (1)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaAgentApp.kt (1)

297-304: Remove unused parameters workspacePath and onAtClick.

These parameters are declared but never used within the function body. If the functionality they represent has been intentionally removed (as suggested by the AI summary regarding disconnected shortcuts), the parameters should be cleaned up to avoid confusion.

 private fun IdeaDevInInputArea(
     project: Project,
     parentDisposable: Disposable,
     isProcessing: Boolean,
     onSend: (String) -> Unit,
     onAbort: () -> Unit,
-    workspacePath: String? = null,
     totalTokens: Int? = null,
     onSettingsClick: () -> Unit = {},
-    onAtClick: () -> Unit = {},
     availableConfigs: List<NamedModelConfig> = emptyList(),
     currentConfigName: String? = null,
     onConfigSelect: (NamedModelConfig) -> Unit = {},
     onConfigureClick: () -> Unit = {}
 )

Also update the call sites at lines 174, 177, 220, and 223 to remove these arguments.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 593d4ca and eeda946.

📒 Files selected for processing (1)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaAgentApp.kt (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.kt

📄 CodeRabbit inference engine (AGENTS.md)

Use expect/actual for platform-specific code in KMP projects (e.g., file I/O on JVM/JS/Wasm)

Files:

  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaAgentApp.kt
🧬 Code graph analysis (1)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaAgentApp.kt (3)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/components/IdeaVerticalResizableSplitPane.kt (1)
  • IdeaVerticalResizableSplitPane (36-140)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/components/timeline/IdeaTimelineContent.kt (2)
  • IdeaTimelineContent (21-50)
  • IdeaEmptyStateMessage (94-108)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/remote/IdeaRemoteAgentContent.kt (2)
  • IdeaRemoteAgentContent (30-96)
  • getEffectiveProjectId (313-324)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build (241)
  • GitHub Check: Build (223)
🔇 Additional comments (3)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaAgentApp.kt (3)

151-187: LGTM on the split pane integration for CODING/LOCAL_CHAT.

The resizable split pane setup with timeline content above and input area below is well-structured. The 75% initial ratio provides a reasonable default for viewing conversation history.


188-234: LGTM on the REMOTE agent split pane integration.

The remote agent implementation correctly handles the project ID derivation and includes appropriate error messaging when the project identifier is blank.


365-383: LGTM on toolbar integration.

The toolbar correctly uses the isProcessing parameter for sendEnabled (which updates on recomposition), and the onSendClick handler sensibly reads from the editor directly with inputText as fallback.

- Change SwingPanel from fixed height (120.dp) to weight(1f) for dynamic sizing
- Change Column modifier from fillMaxWidth to fillMaxSize
- Remove fixed preferredSize from JPanel wrapper
- EditorTextField now properly resizes when dragging the split pane divider
@phodal
Copy link
Member Author

phodal commented Dec 1, 2025

augment review

Copy link

@augmentcode augmentcode bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 3 suggestions posted.

Comment augment review to trigger a new review at any time.

mcpServers = newMcpServers
)

ConfigManager.saveToolConfig(updatedConfig)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ConfigManager.saveToolConfig(updatedConfig) is executed from a Compose scope (likely EDT); file I/O and JSON work on the UI thread can freeze the IDE—consider offloading auto-save to a background dispatcher or IntelliJ background task to avoid EDT violations. (Guideline: edt_violations, background_task_handling)

🤖 Was this useful? React with 👍 or 👎


try {
// Use incremental loading
mcpLoadingState = McpToolConfigManager.discoverMcpToolsIncremental(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

McpToolConfigManager.discoverMcpToolsIncremental(...) may perform network/disk operations and is launched on the Compose scope (EDT); running this on the UI thread risks UI stalls—consider moving it to a background context. (Also applies to the reload call below.) (Guideline: edt_violations, background_task_handling)

🤖 Was this useful? React with 👍 or 👎

0 -> McpToolsTab(
mcpTools = mcpTools,
mcpLoadingState = mcpLoadingState,
onToolToggle = { toolName, enabled ->
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In onToolToggle, toggling by tool.name updates all servers with the same tool name; this can unintentionally flip multiple entries. Consider scoping toggles by server (e.g., include serverName) to avoid cross‑server side effects.

🤖 Was this useful? React with 👍 or 👎

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaAgentApp.kt (2)

118-134: DisposableEffect disposes the wrong ViewModels and leaks the active one

When DisposableEffect(currentAgentType) detects a key change, the onDispose lambda executes with the previous currentAgentType value (the value captured when the effect was created), not the new one. This causes:

  • The ViewModel for the departing tab is never disposed (because the condition is false)
  • The ViewModels for other tabs—including the one being switched to—are disposed (because conditions are true)
  • Result: resource leak and a freshly-created ViewModel is immediately torn down before it can be used

The suggested fix is correct: unconditionally dispose all ViewModels in onDispose, allowing the LaunchedEffect below to handle lazy creation with its null checks. This ensures proper cleanup on each agent-type change and on final teardown.


291-385: The input listener's isProcessing check is stale and allows double-sends via Enter key

In IdeaDevInInputArea, the IdeaInputListener.onSubmit registered in the SwingPanel factory captures isProcessing at factory time. Because SwingPanel.factory runs exactly once and is never re-run on recomposition, this listener will always use the original isProcessing value, even after the parameter changes. This means:

  • Pressing Enter while an execution is in progress will still send, if the Swing component was created when isProcessing was false.
  • This diverges from the bottom toolbar, where sendEnabled correctly disables the button when isProcessing changes.

Fix by using rememberUpdatedState to capture the latest value:

val isProcessingState = rememberUpdatedState(isProcessing)
// In listener:
if (text.isNotBlank() && !isProcessingState.value) {
🧹 Nitpick comments (1)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaAgentApp.kt (1)

151-251: Split-pane layout is solid; consider gating REMOTE sends on connectivity

The new IdeaVerticalResizableSplitPane usage for CODING/LOCAL_CHAT and REMOTE reads clean and matches the existing split-pane patterns (e.g., code review). The timeline/input separation, ratios, and weight usage look good.

One improvement for the REMOTE branch: you already collect remoteIsConnected but do not use it when sending. Today the user can submit tasks while disconnected and only gets a “project or Git URL” error, not a connectivity hint.

You could gate sending on connectivity and surface a clearer message:

             IdeaDevInInputArea(
                 project = project,
                 parentDisposable = viewModel,
                 isProcessing = remoteIsExecuting,
                 onSend = { task ->
-                    val effectiveProjectId = getEffectiveProjectId(remoteProjectId, remoteGitUrl)
-                    if (effectiveProjectId.isNotBlank()) {
-                        remoteVm.executeTask(effectiveProjectId, task, remoteGitUrl)
-                    } else {
-                        remoteVm.renderer.renderError("Please provide a project or Git URL")
-                    }
+                    if (!remoteIsConnected) {
+                        remoteVm.renderer.renderError("Please connect to the remote agent server first")
+                        return@IdeaDevInInputArea
+                    }
+
+                    val effectiveProjectId = getEffectiveProjectId(remoteProjectId, remoteGitUrl)
+                    if (effectiveProjectId.isNotBlank()) {
+                        remoteVm.executeTask(effectiveProjectId, task, remoteGitUrl)
+                    } else {
+                        remoteVm.renderer.renderError("Please provide a project ID or Git URL")
+                    }
                 },

This keeps the new layout intact while tightening the REMOTE UX.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eeda946 and 697d449.

📒 Files selected for processing (1)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaAgentApp.kt (4 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.kt

📄 CodeRabbit inference engine (AGENTS.md)

Use expect/actual for platform-specific code in KMP projects (e.g., file I/O on JVM/JS/Wasm)

Files:

  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaAgentApp.kt
🧬 Code graph analysis (1)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaAgentApp.kt (3)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/components/IdeaVerticalResizableSplitPane.kt (1)
  • IdeaVerticalResizableSplitPane (36-140)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/remote/IdeaRemoteAgentContent.kt (2)
  • IdeaRemoteAgentContent (30-96)
  • getEffectiveProjectId (313-324)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/codereview/IdeaCodeReviewContent.kt (1)
  • IdeaCodeReviewContent (20-77)
🔇 Additional comments (2)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/toolwindow/IdeaAgentApp.kt (2)

19-19: Import of IdeaVerticalResizableSplitPane looks correct

The new import aligns with the component definition under cc.unitmesh.devins.idea.components and its usage below; no issues here.


310-317: SwingPanel sizing and layout integration look good

The changes to wrap IdeaDevInInput in a JPanel with a minimal Dimension(200, 60) and to let it fill via Modifier.fillMaxWidth().weight(1f) integrate well with the split-pane layout and avoid hardcoded preferred sizes. This should behave nicely under resizing.

Also applies to: 352-357

…input

- Add alignment = BottomStart to Popup to make it appear above the selector
- This prevents the dropdown from covering the input area when opened
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaModelSelector.kt (4)

20-20: Redundant import alias.

Line 13 already imports androidx.compose.ui.Alignment, and line 20 creates an alias ComposeAlignment for the same type. This alias is only used once (line 100), while the unqualified Alignment is used elsewhere (lines 72, 185). Remove the alias and use the unqualified Alignment throughout for consistency.

Apply this diff to remove the redundant alias:

-import androidx.compose.ui.Alignment as ComposeAlignment

Then update line 100:

-                alignment = ComposeAlignment.BottomStart,
+                alignment = Alignment.BottomStart,

64-69: Consider using background color tokens instead of border color.

Using JewelTheme.globalColors.borders.normal for the hover background is semantically incorrect. Border colors are typically distinct from background/overlay colors in design systems. Consider using an appropriate background or overlay color token to ensure the component remains theme-consistent.

Also, simplify the transparent color on line 68:

-                        androidx.compose.ui.graphics.Color.Transparent
+                        Color.Transparent

62-94: Consider extracting design values into theme tokens.

Multiple hardcoded values appear throughout the component (sizes: 6.dp, 8.dp, 4.dp, 14.dp; alphas: 0.7f, 0.6f; fontSize: 12.sp). While functional, extracting these into theme tokens or constants would improve maintainability and design consistency across the codebase.


75-80: Consider adding content description for the SmartToy icon.

The SmartToy icon provides semantic meaning (AI/model indicator) but has contentDescription = null. While the adjacent text provides context, adding a description like "Model" would improve accessibility for screen reader users.

             Icon(
                 imageVector = IdeaComposeIcons.SmartToy,
-                contentDescription = null,
+                contentDescription = "Model",
                 tint = JewelTheme.globalColors.text.normal.copy(alpha = 0.7f),
                 modifier = Modifier.size(14.dp)
             )
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 697d449 and a989c1f.

📒 Files selected for processing (1)
  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaModelSelector.kt (5 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.kt

📄 CodeRabbit inference engine (AGENTS.md)

Use expect/actual for platform-specific code in KMP projects (e.g., file I/O on JVM/JS/Wasm)

Files:

  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaModelSelector.kt
🧠 Learnings (1)
📚 Learning: 2025-11-30T02:30:49.805Z
Learnt from: CR
Repo: phodal/auto-dev-sketch PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-30T02:30:49.805Z
Learning: Applies to **/src/{androidMain,desktopMain}/**/*.kt : For Compose (Desktop/Android), use `AutoDevColors` from `cc.unitmesh.devins.ui.compose.theme` or `MaterialTheme.colorScheme`

Applied to files:

  • mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaModelSelector.kt
🔇 Additional comments (1)
mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaModelSelector.kt (1)

158-215: LGTM!

The IdeaDropdownMenuItem helper is well-implemented with proper state handling for enabled/disabled/selected states, conditional styling, and appropriate use of modifiers.

Comment on lines +97 to +100
// Dropdown popup - positioned above the selector to avoid covering input area
if (expanded) {
Popup(
alignment = ComposeAlignment.BottomStart,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "IdeaModelSelector.kt" | head -5

Repository: phodal/auto-dev-sketch

Length of output: 144


🏁 Script executed:

find . -type f -name "IdeaModelSelector.kt" -exec cat -n {} \; | sed -n '85,115p'

Repository: phodal/auto-dev-sketch

Length of output: 1581


🏁 Script executed:

find . -path "*/mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaModelSelector.kt" 2>/dev/null

Repository: phodal/auto-dev-sketch

Length of output: 144


🏁 Script executed:

fd "IdeaModelSelector.kt" 2>/dev/null

Repository: phodal/auto-dev-sketch

Length of output: 142


🏁 Script executed:

ls -la mpp-idea/ 2>/dev/null || echo "Directory not found"

Repository: phodal/auto-dev-sketch

Length of output: 370


🏁 Script executed:

git ls-files | grep -i "IdeaModelSelector" | head -5

Repository: phodal/auto-dev-sketch

Length of output: 142


🏁 Script executed:

rg -l "ComposeAlignment" --type=kt 2>/dev/null | head -10

Repository: phodal/auto-dev-sketch

Length of output: 48


🏁 Script executed:

rg "IdeaModelSelector" --type=kt -l 2>/dev/null | head -5

Repository: phodal/auto-dev-sketch

Length of output: 48


🏁 Script executed:

git ls-files "*.kt" | head -20

Repository: phodal/auto-dev-sketch

Length of output: 1395


🏁 Script executed:

rg -nP --type=kt "Popup\s*\(" -A 10 | grep -E "(Popup|alignment|Alignment)" | head -30

Repository: phodal/auto-dev-sketch

Length of output: 92


🌐 Web query:

ComposeAlignment BottomStart popup positioning behavior

💡 Result:

Short answer: Popup alignment (e.g. Alignment.BottomStart) positions the popup relative to its anchor by computing an anchor point and a popup point and placing the popup so those points coincide, then applying the IntOffset (respecting LTR/RTL). Concretely the code computes:

position = anchorBounds.topLeft + anchorAlignmentPoint + popupAlignmentPoint + resolvedUserOffset.

  • anchorAlignmentPoint is where the chosen Alignment maps inside the anchor bounds.
  • popupAlignmentPoint is the negative of where the same Alignment maps inside the popup content (so the two alignment points line up).
  • resolvedUserOffset applies X flipped in RTL, Y unchanged. (android.googlesource.com)

Implication for Alignment.BottomStart:

  • the anchor point is the anchor's bottom‑start corner; the popup point is the popup's bottom‑start corner (so the popup is placed with its bottom‑start at the anchor's bottom‑start), then offset is applied. In LTR start = left; in RTL start = right. (composables.com)

If you need popup to appear adjacent (outside) the anchor or to auto‑flip when there’s not enough space, use a custom PopupPositionProvider or one of the position providers (e.g., for dropdowns/context menus). The PopupPositionProvider API exposes anchorBounds and windowSize to compute alternative placements. (developer.android.com)

If you want, tell me which behavior you’re seeing and I’ll help diagnose with specific code.

Citations:


🏁 Script executed:

rg "BottomStart|TopStart|positioned.*above|positioned.*below" --type=kt 2>/dev/null | head -20

Repository: phodal/auto-dev-sketch

Length of output: 48


🏁 Script executed:

rg "Dropdown popup|positioned above|avoid covering input" --type=kt 2>/dev/null

Repository: phodal/auto-dev-sketch

Length of output: 48


🏁 Script executed:

git ls-files | grep "\.kt$" | wc -l

Repository: phodal/auto-dev-sketch

Length of output: 70


Comment contradicts popup alignment.

Line 97 states the popup is "positioned above the selector," but ComposeAlignment.BottomStart on line 100 places the popup below the anchor (its bottom-start corner aligns with the anchor's bottom-start corner). To actually position above as intended, use ComposeAlignment.TopStart or provide a custom PopupPositionProvider with upward offset logic.

🤖 Prompt for AI Agents
In mpp-idea/src/main/kotlin/cc/unitmesh/devins/idea/editor/IdeaModelSelector.kt
around lines 97 to 100, the comment says the dropdown popup should be
"positioned above the selector" but the code uses ComposeAlignment.BottomStart
which places the popup below; change the alignment to ComposeAlignment.TopStart
to align the popup's top-start to the anchor (placing it above), or if more
precise control is required implement and pass a PopupPositionProvider that
calculates an upward offset from the anchor to ensure the popup sits above the
selector even when space constraints occur.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates the complete DevInEditorInput functionality from the mpp-ui module to the mpp-idea module, introducing IntelliJ IDEA-specific integrations and UI reorganization. The changes replace the previous Compose-only input with a hybrid Swing/Compose solution that leverages IntelliJ's native editor infrastructure for better DevIn language support.

Key Changes:

  • Integrated resizable split panes for chat-based agent modes (CODING, LOCAL_CHAT, REMOTE)
  • Created new dialogs for prompt optimization and MCP configuration with auto-save
  • Enhanced DevIn input with auto-completion triggers and dynamic file type detection
  • Reorganized toolbar layout with model selector moved to left, MCP settings and prompt optimization to right

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
IdeaComposeIcons.kt Added 6 new Material Design icons (SmartToy, AutoAwesome, ContentPaste, Save, TextFields, InsertDriveFile, Close) for toolbar UI
IdeaAgentApp.kt Replaced fixed Box layout with IdeaVerticalResizableSplitPane for CODING/LOCAL_CHAT/REMOTE modes; moved input area into bottom pane
IdeaTopToolbar.kt NEW - Created top toolbar with @ / triggers and file selection (not yet integrated into UI)
IdeaPromptOptimizationDialog.kt NEW - Side-by-side prompt enhancement dialog with editable output (hardcoded language, missing integration)
IdeaModelSelector.kt Redesigned with transparent background, hover effects, and SmartToy icon; popup alignment issue
IdeaMcpConfigDialog.kt NEW - Two-tab configuration dialog with auto-save and incremental loading (uses println instead of Logger)
IdeaInputSection.kt DELETED - Removed pure Compose input in favor of Swing-based DevIn editor
IdeaDevInInput.kt Added DevIn file type detection, PsiDocumentManager integration, and auto-completion triggers (trigger logic bug)
IdeaBottomToolbar.kt Removed @ / buttons and workspace indicator; added prompt optimization button (not connected)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

* Layout: @ - / - Clipboard - Save - Cursor | Selected Files... | Add
*/
@Composable
fun IdeaTopToolbar(
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The IdeaTopToolbar component is defined but never integrated into the UI. According to the comment in IdeaBottomToolbar, the @ and / triggers were moved to this toolbar, but it's not being used anywhere in IdeaDevInInputArea or the main application flow.

Copilot uses AI. Check for mistakes.
Comment on lines +195 to +197
IconButton(onClick = onDismiss) {
Text("×")
}
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The close button uses a text "×" symbol without proper accessibility description. Consider using an actual Icon component with a proper contentDescription parameter (e.g., contentDescription = "Close dialog") to improve accessibility for screen readers.

Copilot uses AI. Check for mistakes.
isEnhancing = true
errorMessage = null
try {
val enhanced = enhancer.enhance(originalText.trim(), "zh")
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The language parameter is hardcoded to "zh" (Chinese). This should either be configurable, derived from the IDE's locale settings, or default to a more neutral language like "en". Hardcoding "zh" may produce unexpected results for non-Chinese users.

Copilot uses AI. Check for mistakes.
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import cc.unitmesh.llm.KoogLLMService
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import: KoogLLMService is imported but not used in this file. Consider removing it to keep the imports clean.

Suggested change
import cc.unitmesh.llm.KoogLLMService

Copilot uses AI. Check for mistakes.
Comment on lines +105 to +108
println("✅ Auto-saved tool configuration")
}
} catch (e: Exception) {
println("❌ Auto-save failed: ${e.message}")
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug print statements should be replaced with proper logging using IntelliJ's logging framework (e.g., Logger.getInstance(IdeaMcpConfigDialog::class.java)). This ensures consistent logging behavior and allows users to control log levels through IDE settings.

Copilot uses AI. Check for mistakes.
Comment on lines +152 to +159
println("❌ Error loading MCP tools: ${e.message}")
}
}
}

isLoading = false
} catch (e: Exception) {
println("Error loading tool config: ${e.message}")
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug print statements should be replaced with proper logging using IntelliJ's logging framework (e.g., Logger.getInstance(IdeaMcpConfigDialog::class.java)). This ensures consistent logging behavior and allows users to control log levels through IDE settings.

Copilot uses AI. Check for mistakes.
onSlashClick: () -> Unit = {},
onSettingsClick: () -> Unit = {},
workspacePath: String? = null,
onPromptOptimizationClick: () -> Unit = {},
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The onPromptOptimizationClick parameter in IdeaBottomToolbar is not connected to any functionality. The prompt optimization dialog (IdeaPromptOptimizationDialog) is not instantiated or triggered anywhere in the codebase, making this button non-functional.

Copilot uses AI. Check for mistakes.
// Dropdown popup - positioned above the selector to avoid covering input area
if (expanded) {
Popup(
alignment = ComposeAlignment.BottomStart,
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The popup alignment is set to BottomStart, which positions the popup below the selector. However, the comment on line 97 states the popup should be "positioned above the selector to avoid covering input area." The alignment should be TopStart to match the intended behavior.

Suggested change
alignment = ComposeAlignment.BottomStart,
alignment = ComposeAlignment.TopStart,

Copilot uses AI. Check for mistakes.
Comment on lines +86 to +88
IconButton(onClick = onDismiss) {
Text("×")
}
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The close button uses a text "×" symbol without proper accessibility description. Consider using an actual Icon component with a proper contentDescription parameter (e.g., contentDescription = "Close dialog") to improve accessibility for screen readers.

Copilot uses AI. Check for mistakes.
currentEditor.caretModel.moveToOffset(document.textLength)

// Auto-trigger completion for special characters
if (textToAppend in listOf("@", "/", "$", ":")) {
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The auto-trigger completion logic checks if the entire textToAppend string matches a trigger character, but if multiple characters are appended at once (e.g., "abc@"), the completion won't trigger. Consider checking if textToAppend contains or ends with a trigger character instead: if (textToAppend.lastOrNull() in listOf('@', '/', '$', ':')).

Suggested change
if (textToAppend in listOf("@", "/", "$", ":")) {
if (textToAppend.lastOrNull() in listOf('@', '/', '$', ':')) {

Copilot uses AI. Check for mistakes.
Integrates DevIn language for completion and syntax highlighting, replaces kotlinx.serialization with Gson for JSON handling, updates dependencies, and improves Gradle configuration.
Define required extension points in plugin.xml to support devins-lang integration.
@phodal phodal merged commit 160e8fa into master Dec 1, 2025
2 of 3 checks passed
@phodal phodal deleted the feature/idea-devin-editor-input branch December 2, 2025 10:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant